home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 16 / CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso / CUCD / Graphics / Ghostscript / source / gdevpdft.c < prev    next >
C/C++ Source or Header  |  1997-07-22  |  7KB  |  227 lines

  1. /* Copyright (C) 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevpdft.c */
  20. /* Text handling for PDF-writing driver. */
  21. #include "math_.h"
  22. #include "string_.h"
  23. #include "gx.h"
  24. #include "gserrors.h"
  25. #include "gsutil.h"            /* for bytes_compare */
  26. #include "gdevpdfx.h"
  27. #include "strimpl.h"
  28. #include "sstring.h"            /* for PSStringEncode */
  29.  
  30. /*
  31.  * Define whether to re-encode characters in order to find them within base
  32.  * font encodings.  This can greatly reduce the number of characters
  33.  * represented as bitmaps, but it may cause the text in the PDF file to
  34.  * differ from the text in the PostScript input.
  35.  */
  36. #define RE_ENCODE_OK
  37.  
  38. /*
  39.  * The show pseudo-parameter is currently the way that the PostScript code
  40.  * passes show operations to the PDF writer.  It is a hack!  Its "value"
  41.  * is a dictionary with the following keys and values:
  42.  *    /String (str)
  43.  *    /Values [cx cy char ax ay px py]
  44.  *    /Matrix [xx xy yx yy tx ty]
  45.  *    /FontName /fontname
  46.  *    /Encoding [e0 .. e255]
  47.  *    /BaseEncoding [e0 ... e255]
  48.  * Note that px/y and tx/y are floating point values in device space;
  49.  * cx/y and ax/y are in text space.  The matrix is the concatenation of
  50.  *    FontMatrix
  51.  *    inverse of base FontMatrix
  52.  *    CTM
  53.  * This represents the transformation from a 1-unit-based character space
  54.  * to device space.  The base encoding is StandardEncoding for all fonts
  55.  * except Symbol and ZapfDingbats.
  56.  */
  57.  
  58. /* Define the 14 standard built-in fonts. */
  59. private const char *standard_font_names[] = {
  60.   "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
  61.   "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique",
  62.   "Symbol",
  63.   "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",
  64.   "ZapfDingbats",
  65.   0
  66. };
  67.  
  68. /* Process a show operation. */
  69. int
  70. pdfshow_process(gx_device_pdf *pdev, const gs_param_dict *ptd)
  71. {
  72. #define plist (ptd->list)
  73.     gs_param_string str, fnstr;
  74.     gs_param_float_array va;
  75. #define v_cx va.data[0]
  76. #define v_cy va.data[1]
  77. #define v_cch (int)va.data[2]
  78. #define v_ax va.data[3]
  79. #define v_ay va.data[4]
  80. #define v_px va.data[5]
  81. #define v_py va.data[6]
  82.     gs_param_float_array ma;
  83.     gs_param_string_array ea, bea;
  84.     int code;
  85.     pdf_font *ppf;
  86.     stream *s = pdev->strm;
  87.     double sx = pdev->scale.x, sy = pdev->scale.y;
  88.     bool re_encode = false;
  89.     float size;
  90.     byte strbuf[200];
  91.  
  92.     if ( (code = param_read_string(plist, "String", &str)) ||
  93.          (code = param_read_float_array(plist, "Values", &va)) ||
  94.          va.size != 7 ||
  95.          (code = param_read_float_array(plist, "Matrix", &ma)) ||
  96.          ma.size != 6 ||
  97.          (code = param_read_string(plist, "FontName", &fnstr)) ||
  98.          (code = param_read_name_array(plist, "Encoding", &ea)) ||
  99.          ea.size != 256 ||
  100.          (code = param_read_name_array(plist, "BaseEncoding", &bea)) ||
  101.          bea.size != 256
  102.        )
  103.       return_error(gs_error_rangecheck);
  104.     if ( v_cy != 0 || (v_cch != 32 && v_cx != 0) || v_ay != 0 )
  105.       return_error(gs_error_undefined);
  106.     /* Check that all characters match the base encoding. */
  107.     { uint i;
  108.       for ( i = 0; i < str.size; ++i )
  109.         { byte chr = str.data[i];
  110.           if ( ea.data[chr].data != bea.data[chr].data )
  111.         {
  112. #ifdef RE_ENCODE_OK
  113.           /* Since the penalty for converting text to a bitmap */
  114.           /* is so severe, see if the character is present */
  115.           /* at some other position in the base encoding. */
  116.           int ei;
  117.           for ( ei = 0; ei < 256; ++ei )
  118.             if ( ea.data[chr].data == bea.data[ei].data )
  119.               break;
  120.           if ( ei == 256 )
  121.             return_error(gs_error_undefined);
  122.           /* It really simplifies things if we can buffer */
  123.           /* the entire string locally in one piece.... */
  124.           if ( !re_encode )
  125.             { if ( str.size > sizeof(strbuf) )
  126.                 return_error(gs_error_limitcheck);
  127.               memcpy(strbuf, str.data, str.size);
  128.               re_encode = true;
  129.             }
  130.           strbuf[i] = (byte)ei;
  131. #else
  132.           return_error(gs_error_undefined);
  133. #endif
  134.         }
  135.         }
  136.     }
  137.     /* Find or create the font resource. */
  138.     for ( ppf = (pdf_font *)pdev->resources[resourceFont]; ppf != 0;
  139.           ppf = ppf->next
  140.         )
  141.       if ( !bytes_compare(ppf->fname.data, ppf->fname.size,
  142.                   fnstr.data, fnstr.size)
  143.          )
  144.         break;
  145.     /* Try to find a reasonable size value.  This isn't necessary, */
  146.     /* but it's worth the effort. */
  147.     size = fabs(ma.data[0]) / sx;
  148.     if ( size < 0.01 )
  149.       size = fabs(ma.data[1]) / sy;
  150.     if ( size < 0.01 )
  151.       size = 1;
  152.     if ( ppf == 0 )
  153.     {    /* Currently, we only handle the built-in fonts. */
  154.         const char **ppfn;
  155.         for ( ppfn = standard_font_names; *ppfn; ++ppfn )
  156.           if ( strlen(*ppfn) == fnstr.size &&
  157.                !strncmp(*ppfn, (const char *)fnstr.data, fnstr.size)
  158.              )
  159.             break;
  160.         if ( !*ppfn )
  161.           return_error(gs_error_undefined);
  162.         code = pdf_begin_resource(pdev, resourceFont,
  163.                       (pdf_resource **)&ppf);
  164.         if ( code < 0 )
  165.           return_error(gs_error_undefined);
  166.         pprints1(s, " /Subtype /Type1 /BaseFont /%s >>\n",
  167.              *ppfn);
  168.         ppf->fname.data = fnstr.data, ppf->fname.size = fnstr.size;
  169.         pdf_end_resource(pdev);
  170.     }
  171.     code = pdf_open_contents(pdev, pdf_in_text);
  172.     if ( code < 0 )
  173.       return code;
  174.     /* We attempt to eliminate redundant parameter settings. */
  175.     if ( ppf != pdev->text_state.font || size != pdev->text_state.size )
  176.       { pprintld1(s, "/R%ld ", ppf->id);
  177.         pprintg1(s, "%g Tf\n", size);
  178.         pdev->text_state.font = ppf;
  179.         pdev->text_state.size = size;
  180.       }
  181.     sx *= size;
  182.     sy *= size;
  183.     { gs_matrix tmat;
  184.  
  185.       tmat.xx = ma.data[0] / sx;
  186.       tmat.xy = ma.data[1] / sy;
  187.       tmat.yx = ma.data[2] / sx;
  188.       tmat.yy = ma.data[3] / sy;
  189.       tmat.tx = (v_px + ma.data[4]) / pdev->scale.x;
  190.       tmat.ty = (v_py + ma.data[5]) / pdev->scale.y;
  191.       pprintg6(s, "%g %g %g %g %g %g Tm\n",
  192.            tmat.xx, tmat.xy, tmat.yx, tmat.yy, tmat.tx, tmat.ty);
  193.       { float chars = v_ax * size;
  194.         if ( pdev->text_state.character_spacing != chars )
  195.           { pprintg1(s, "%g Tc\n", chars);
  196.             pdev->text_state.character_spacing = chars;
  197.           }
  198.       }
  199.       { float words = v_cx * size;
  200.         if ( pdev->text_state.word_spacing != words )
  201.           { pprintg1(s, "%g Tw\n", words);
  202.             pdev->text_state.word_spacing = words;
  203.           }
  204.       }
  205.     }
  206.     /* Write the string.  Make sure it gets any necessary \s. */
  207.     pputc(s, '(');
  208.     { byte buf[100];        /* size is arbitrary */
  209.       stream_cursor_read r;
  210.       stream_cursor_write w;
  211.       int status;
  212.  
  213.       r.ptr = (re_encode ? strbuf : str.data) - 1;
  214.       r.limit = r.ptr + str.size;
  215.       w.limit = buf + sizeof(buf) - 1;
  216.       do
  217.         { w.ptr = buf - 1;
  218.           status = (*s_PSSE_template.process)(NULL, &r, &w, true);
  219.           pwrite(s, buf, (uint)(w.ptr + 1 - buf));
  220.         }
  221.       while ( status == 1 );
  222.     }
  223.     pputs(s, " Tj\n");
  224.  
  225.     return 0;
  226. }
  227.